package com.lzc.tlmail.tlmailorder.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.lzc.common.constant.OrderConstant;
import com.lzc.common.exception.NoSuchWareException;
import com.lzc.common.exception.RRException;
import com.lzc.common.to.SkuWareVo;
import com.lzc.common.to.mq.Orderto;
import com.lzc.common.to.mq.Seckillto;
import com.lzc.common.utils.R;
import com.lzc.common.vo.MemberEntityVo;
import com.lzc.tlmail.tlmailorder.config.ThreadPoolConfigProperties;
import com.lzc.tlmail.tlmailorder.entity.OrderItemEntity;
import com.lzc.tlmail.tlmailorder.enume.OrderStatusEnum;
import com.lzc.tlmail.tlmailorder.feign.MemberFeignService;
import com.lzc.tlmail.tlmailorder.feign.CartFeignService;
import com.lzc.tlmail.tlmailorder.feign.ProductFeignService;
import com.lzc.tlmail.tlmailorder.feign.WareFeignService;
import com.lzc.tlmail.tlmailorder.interceptor.OrderInterceptor;
import com.lzc.tlmail.tlmailorder.service.OrderItemService;
import com.lzc.tlmail.tlmailorder.vo.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lzc.common.utils.PageUtils;
import com.lzc.common.utils.Query;

import com.lzc.tlmail.tlmailorder.dao.OrderDao;
import com.lzc.tlmail.tlmailorder.entity.OrderEntity;
import com.lzc.tlmail.tlmailorder.service.OrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {
    @Autowired
    private MemberFeignService memberFeignService;
    @Autowired
    private CartFeignService cartFeignService;
    @Autowired
    private ThreadPoolExecutor executor;
    @Autowired
    private WareFeignService wareFeignService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ProductFeignService productFeignService;
    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 得到的订单所需数据
     * @return
     */
    @Override
    public OrderItemvo getOrder() throws ExecutionException, InterruptedException {
        MemberEntityVo memberEntityVo = OrderInterceptor.userInfotoThreadLocal.get();
        OrderItemvo orderItemvo = new OrderItemvo();
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        CompletableFuture<Void> getAddressFuture = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(attributes);
            //先获取用户地址
            List<MemberAddressvo> memberAddressvos = memberFeignService.memberReceiveAddressInfo(memberEntityVo.getId());
            orderItemvo.setMemberAddressvos(memberAddressvos);
        }, executor);
        CompletableFuture<Void> getCartsFuture = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(attributes);
            //获取购物车内容
            List<OrderCartSkuvo> cartItems = cartFeignService.getCartItems();
            orderItemvo.setOrderCartSkuvos(cartItems);
        }, executor).thenRunAsync(()->{
            List<OrderCartSkuvo> orderCartSkuvos = orderItemvo.getOrderCartSkuvos();
            if(orderCartSkuvos!=null&&orderCartSkuvos.size()>0){
                List<Long> collect = orderCartSkuvos.stream().map(item -> item.getSkuId()).collect(Collectors.toList());
                List<SkuWareVo> skusHasStock = wareFeignService.getSkusHasStock(collect);
                Map<Long, Boolean> collect1 = skusHasStock.stream().collect(Collectors.toMap(SkuWareVo::getSkuId, SkuWareVo::getHasStock));
                orderItemvo.setWareMap(collect1);
            }
                }
        );

        CompletableFuture.allOf(getAddressFuture,getCartsFuture).get();

        //积分

        //价格等

        //防重令牌 给redis一份 页面一份 页面提交的时候带上令牌跟redis对比判断
        String replace = UUID.randomUUID().toString().replace("-", "");

        redisTemplate.opsForValue().set(OrderConstant.ORDER_USER_TOKEN+memberEntityVo.getId(),replace);
        orderItemvo.setOrderToken(replace);
        orderItemvo.setIntegration(memberEntityVo.getIntegration());
        return orderItemvo;
    }

    /**
     * 订单下单功能
     * @param submitOrdervo
     * @return
     */
    @Transactional
    @Override
    public OrderSubmitrspnvo orderSubmit(SubmitOrdervo submitOrdervo) {
        OrderSubmitrspnvo submitrspnvo = new OrderSubmitrspnvo();
        MemberEntityVo memberEntityVo = OrderInterceptor.userInfotoThreadLocal.get();
        submitrspnvo.setResultCode(0);
        //先验令牌
        //1保证原子性   使用以下脚本 返回都是0 或 1
        String script="if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
        String orderToken = submitOrdervo.getOrderToken();
        //原子验证令牌和删除令牌
        Long result = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList(OrderConstant.ORDER_USER_TOKEN + memberEntityVo.getId()), orderToken);
        if(result==0){
            submitrspnvo.setResultCode(1);
            return submitrspnvo;
        }else {
            //构建订单(订单包含订单和订单项)
            String ordersn = IdWorker.getTimeId();
            OrderEntity orderEntity=createOrder(ordersn);
            orderEntity.setPayType(submitOrdervo.getPayType());
            //再放地址
            R addressinfo = memberFeignService.getAddressinfoById(submitOrdervo.getAddId());
            MemberAddressvo addressvo = addressinfo.getData("data", new TypeReference<MemberAddressvo>() {
            });
            orderEntity.setReceiverName(addressvo.getName());
            orderEntity.setReceiverPhone(addressvo.getPhone());
            orderEntity.setReceiverPostCode(addressvo.getPostCode());
            orderEntity.setReceiverProvince(addressvo.getProvince());
            orderEntity.setReceiverCity(addressvo.getCity());
            orderEntity.setReceiverRegion(addressvo.getRegion());
            orderEntity.setReceiverDetailAddress(addressvo.getDetailAddress());
            orderEntity.setNote("备注zzzzzzzzz");
            orderEntity.setDeleteStatus(0);
            orderEntity.setModifyTime(new Date());
            //构建订单项
           List<OrderItemEntity> orderItemEntities=buildOrderItems(ordersn);
            //价格等其他的
            buildOrderPrice(orderEntity,orderItemEntities);
            //验价
            BigDecimal payAmount = orderEntity.getPayAmount();
            BigDecimal payPrice = submitOrdervo.getPayPrice();
            if(Math.abs(payAmount.subtract(payPrice).doubleValue())<0.1){
                this.save(orderEntity);//保存订单
                orderItemService.saveBatch(orderItemEntities);//保存订单项
                //TODO 锁定库存 买了几件商品 就要给对应的sku库存累加几件商品 并且加起来之后不能大于总库存 大于就失败
                LockWareOrdervo lockWareOrdervo = new LockWareOrdervo();
                lockWareOrdervo.setOrdersn(ordersn);
                List<OrderCartSkuvo> cartSkuvos = orderItemEntities.stream().map(item -> {
                    OrderCartSkuvo orderCartSkuvo = new OrderCartSkuvo();
                    orderCartSkuvo.setSkuId(item.getSkuId());
                    orderCartSkuvo.setCount(item.getSkuQuantity());
                    orderCartSkuvo.setSkuTitle(item.getSkuName());
                    return orderCartSkuvo;
                }).collect(Collectors.toList());
                lockWareOrdervo.setOrderCartSkuvos(cartSkuvos);
                //远程锁库存
                R r = wareFeignService.lockWareOrder(lockWareOrdervo);
                if(r.getCode()==0){
                    submitrspnvo.setOrderEntity(orderEntity);
                    //这里下单成功 之后发送消息去延时队列 之后监听队列要释放的做后面的业务操作
                    Orderto orderto = new Orderto();
                    BeanUtils.copyProperties(orderEntity,orderto);
                    rabbitTemplate.convertAndSend("order-event-exchange","order.create.order",orderto);
                    return submitrspnvo;
                }else {
                    submitrspnvo.setResultCode(3);
                    throw new RRException("库存不足",500);
                }
            }else {
                submitrspnvo.setResultCode(2);
                return submitrspnvo;
            }
        }

    }
    /**
     * 根据订单号得到订单
     * @param ordersn
     * @return
     */
    @Override
    public OrderEntity getOrderStatusByOrdersn(String ordersn) {

        return this.getOne(new LambdaQueryWrapper<OrderEntity>().eq(OrderEntity::getOrderSn,ordersn));
    }

    /**
     * 关单  改变状态
     * @param orderto
     */
    @Override
    public void updateOrderStatus(Orderto orderto) {
        OrderEntity byId = this.getById(orderto.getId());
        if(byId.getStatus()==0){
            OrderEntity orderEntity = new OrderEntity();
            orderEntity.setId(byId.getId());
            orderEntity.setStatus(OrderStatusEnum.CANCLED.getCode());
            this.updateById(orderEntity);
            //发送MQ一个
            Orderto orderto1 = new Orderto();
            BeanUtils.copyProperties(orderEntity,orderto1);
            rabbitTemplate.convertAndSend("order-event-exchange","order.release.other",orderto1);
        }

    }

    /**
     * 获取当前用户的所有订单信息
     * @return
     */
    @Transactional
    @Override
    public List<Ordervo> orderLists(String out_trade_no) {
        MemberEntityVo memberEntityVo = OrderInterceptor.userInfotoThreadLocal.get();
        if(!StringUtils.isEmpty(out_trade_no)){
            this.getBaseMapper().updateStatus(memberEntityVo.getId(),out_trade_no);
        }

        List<OrderEntity> orderEntities = this.list(new LambdaQueryWrapper<OrderEntity>().eq(OrderEntity::getMemberId, memberEntityVo.getId()));
        List<Ordervo> ordervos = orderEntities.stream().map(item -> {
            Ordervo ordervo = new Ordervo();
            BeanUtils.copyProperties(item, ordervo);
           switch (item.getStatus()){
               case 0:
                   ordervo.setStatus("待付款");
                   break;
               case 1:
                   ordervo.setStatus("待发货");
                   break;
               case 2:
                   ordervo.setStatus("已发货");
                   break;
               case 3:
                   ordervo.setStatus("已完成");
                   break;
               case 4:
                   ordervo.setStatus("已关闭");
                   break;
               case 5:
                   ordervo.setStatus("无效订单");
                   break;
           }
            List<OrderItemEntity> orderItemEntities = orderItemService.list(new LambdaQueryWrapper<OrderItemEntity>().eq(OrderItemEntity::getOrderSn, item.getOrderSn()));
            if (orderItemEntities != null && orderItemEntities.size() > 0) {
                ordervo.setOrderItemEntities(orderItemEntities);
                //删除对应购物车信息
                for (OrderItemEntity orderItemEntity : orderItemEntities) {
                    cartFeignService.skuDel(orderItemEntity.getSkuId());
                }
            }
            return ordervo;
        }).collect(Collectors.toList());
        return ordervos;
    }

    /**
     * 处理秒杀下单
     * @param seckillto
     */
    @Override
    public void seckillOrder(Seckillto seckillto) {
        OrderEntity order = new OrderEntity();
        order.setOrderSn(seckillto.getOrdersn());
        BigDecimal bigDecimal = seckillto.getSeckillPrice().multiply(new BigDecimal(seckillto.getNum().toString()));
        order.setPayAmount(bigDecimal);
        this.save(order);
        OrderItemEntity orderItemEntity = new OrderItemEntity();
        orderItemEntity.setOrderSn(seckillto.getOrdersn());
        orderItemEntity.setRealAmount(bigDecimal);
        orderItemService.save(orderItemEntity);
    }


    /**
     * 构建订单相关价格信息
     * @param orderEntity
     * @param orderItemEntities
     */
    private void buildOrderPrice(OrderEntity orderEntity, List<OrderItemEntity> orderItemEntities) {
        BigDecimal orderTotal = new BigDecimal("0");
        Integer integration=new Integer(0);
        Integer growth=new Integer(0);
        for (OrderItemEntity entity : orderItemEntities) {
            if(entity!=null){
                orderTotal=orderTotal.add(entity.getRealAmount());
                integration=entity.getGiftIntegration()+integration;
                growth=entity.getGiftGrowth()+growth;
            }
        }
        orderEntity.setTotalAmount(orderTotal);
        orderEntity.setPayAmount(orderEntity.getTotalAmount());
        orderEntity.setDiscountAmount(orderEntity.getPayAmount());
        orderEntity.setIntegration(integration);
        orderEntity.setGrowth(growth);
    }

    /**
     * 构建所有订单项
     * @param ordersn
     * @return
     */
    private List<OrderItemEntity> buildOrderItems(String ordersn) {

        List<OrderCartSkuvo> cartItems = cartFeignService.getCartItems();
        if(cartItems!=null&&cartItems.size()>0){
            List<OrderItemEntity> orderItemEntities = cartItems.stream().map(item -> {
                OrderItemEntity orderItemEntity = buildOrderItem(item);
                orderItemEntity.setOrderSn(ordersn);
                return orderItemEntity;
            }).collect(Collectors.toList());

            return orderItemEntities;
        }
        return null;
    }

    /**
     * 构建订单项
     * @param cartSku
     * @return
     */
    private OrderItemEntity buildOrderItem(OrderCartSkuvo cartSku) {
        R spuInfo = productFeignService.getSpuInfoBySkuId(cartSku.getSkuId());
        SpuInfovo spuInfoData = spuInfo.getData("data", new TypeReference<SpuInfovo>() {
        });
        //根据skuId得到spu信息
        OrderItemEntity orderItemEntity = new OrderItemEntity();
        orderItemEntity.setSpuId(spuInfoData.getId());
        orderItemEntity.setSpuName(spuInfoData.getSpuName());
        orderItemEntity.setSpuBrand(spuInfoData.getBrandId().toString());
        orderItemEntity.setCategoryId(spuInfoData.getCatalogId());
        orderItemEntity.setSkuId(cartSku.getSkuId());
        orderItemEntity.setSkuPic(cartSku.getDefaultIamge());
        orderItemEntity.setSkuPrice(cartSku.getPrice());
        orderItemEntity.setSkuQuantity(cartSku.getCount());
        //这里是把原来sku的销售属性是一个集合的 然后现在用这个把他拆开用;拼接
        String s = StringUtils.collectionToDelimitedString(cartSku.getAttrs(), ";");
        orderItemEntity.setSkuAttrsVals(s);
        //sku积分那些就不设置了 没做
        //得到sku最后的总价格
        orderItemEntity.setRealAmount(orderItemEntity.getSkuPrice().multiply(new BigDecimal(orderItemEntity.getSkuQuantity().toString())));
        orderItemEntity.setGiftIntegration(orderItemEntity.getRealAmount().intValue());
        orderItemEntity.setGiftGrowth(orderItemEntity.getRealAmount().intValue());
        return orderItemEntity;
    }

    /**
     * 创建订单方法
     * @param ordersn
     * @return
     */
    private OrderEntity createOrder(String ordersn) {
        MemberEntityVo memberEntityVo = OrderInterceptor.userInfotoThreadLocal.get();
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setMemberId(memberEntityVo.getId());
        orderEntity.setOrderSn(ordersn);
        orderEntity.setCreateTime(new Date());
        orderEntity.setMemberUsername(memberEntityVo.getUsername());
        orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        //物流。。。
        orderEntity.setAutoConfirmDay(7);
        return orderEntity;
    }

}